package cn.iocoder.yudao.module.trade.service.fruitcard;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.iocoder.yudao.framework.common.enums.TerminalEnum;
import cn.iocoder.yudao.module.member.api.address.MemberAddressApi;
import cn.iocoder.yudao.module.product.api.sku.ProductSkuApi;
import cn.iocoder.yudao.module.product.api.sku.dto.ProductSkuRespDTO;
import cn.iocoder.yudao.module.trade.dal.dataobject.delivery.DeliveryExpressDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemOtherDO;
import cn.iocoder.yudao.module.trade.dal.mysql.delivery.DeliveryExpressMapper;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderTypeEnum;
import cn.iocoder.yudao.module.trade.framework.order.core.utils.TradeOrderLogUtils;
import com.google.common.collect.Lists;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.RandomUtil;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.yudao.module.member.api.address.dto.MemberAddressRespDTO;
import cn.iocoder.yudao.module.member.api.user.MemberUserApi;
import cn.iocoder.yudao.module.product.api.spu.ProductSpuApi;
import cn.iocoder.yudao.module.product.api.spu.dto.ProductSpuRespDTO;
import cn.iocoder.yudao.module.system.api.dict.DictDataApi;
import cn.iocoder.yudao.module.system.api.dict.dto.DictDataRespDTO;
import cn.iocoder.yudao.module.trade.api.order.TradeOrderApi;
import cn.iocoder.yudao.module.trade.api.order.dto.TradeOrderRespDTO;
import cn.iocoder.yudao.module.trade.controller.admin.fruitcard.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.fruitcard.vo.*;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderCreateReqVO;
import cn.iocoder.yudao.module.trade.controller.app.order.vo.AppTradeOrderSettlementReqVO;
import cn.iocoder.yudao.module.trade.convert.fruitcard.FruitCardUserConvert;
import cn.iocoder.yudao.module.trade.convert.order.TradeOrderConvert;
import cn.iocoder.yudao.module.trade.dal.dataobject.cart.CartDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardDetailMapper;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardMapper;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardUserMapper;
import cn.iocoder.yudao.module.trade.dal.dataobject.fruitcard.FruitCardUsesMapper;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderDO;
import cn.iocoder.yudao.module.trade.dal.dataobject.order.TradeOrderItemDO;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardDO;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardDetailDO;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardUserDO;
import cn.iocoder.yudao.module.trade.dal.mysql.fruitcard.FruitCardUsesDO;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderItemOtherMapper;
import cn.iocoder.yudao.module.trade.dal.mysql.order.TradeOrderMapper;
import cn.iocoder.yudao.module.trade.dal.redis.no.TradeNoRedisDAO;
import cn.iocoder.yudao.module.trade.enums.delivery.DeliveryTypeEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderRefundStatusEnum;
import cn.iocoder.yudao.module.trade.enums.order.TradeOrderStatusEnum;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateService;
import cn.iocoder.yudao.module.trade.service.order.TradeOrderUpdateServiceImpl;
import cn.iocoder.yudao.module.trade.service.order.handler.TradeOrderHandler;
import cn.iocoder.yudao.module.trade.service.price.TradePriceService;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateReqBO;
import cn.iocoder.yudao.module.trade.service.price.bo.TradePriceCalculateRespBO;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;
import org.springframework.validation.annotation.Validated;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import cn.iocoder.yudao.framework.common.pojo.PageResult;


import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.getSumValue;
import static cn.iocoder.yudao.module.trade.enums.ErrorCodeConstants.*;

/**
 * 水果卡 Service 实现类
 *
 * @author 管理员
 */
@Service
@Validated
public class FruitCardUserServiceImpl implements FruitCardUserService {

    @Resource
    private FruitCardUserMapper cardUserMapper;

    @Resource
    private FruitCardDetailMapper fruitCardDetailMapper;

    @Resource
    private MemberUserApi memberUserApi;

    @Resource
    private DictDataApi dataApi;


    @Resource
    private FruitCardMapper fruitCardMapper;

    @Resource
    private ProductSpuApi productSpuApi;
    @Resource
    private ProductSkuApi productSkuApi;

    @Resource
    private TradeOrderApi tradeOrderApi;

    @Resource
    private FruitCardUsesMapper fruitCardUsesMapper;


    @Resource
    private TradeOrderMapper tradeOrderMapper;
    @Resource
    private TradeOrderItemMapper tradeOrderItemMapper;

    @Resource
    private TradeOrderItemOtherMapper tradeOrderItemOtherMapper;
    @Resource
    private TradeNoRedisDAO tradeNoRedisDAO;

    @Resource
    private List<TradeOrderHandler> tradeOrderHandlers;

    @Resource
    private TradePriceService tradePriceService;

    @Resource
    private MemberAddressApi addressApi;

    @Resource
    private DeliveryExpressMapper deliveryExpressMapper;

    @Override
    public Long createCardUser(FruitCardUserCreateReqVO createReqVO) {
        // 插入
        FruitCardUserDO cardUser = FruitCardUserConvert.INSTANCE.convert(createReqVO);
        cardUserMapper.insert(cardUser);
        // 返回
        return cardUser.getId();
    }

    @Override
    public void updateCardUser(FruitCardUserUpdateReqVO updateReqVO) {
        // 校验存在
        validateCardUserExists(updateReqVO.getId());
        // 更新
        FruitCardUserDO updateObj = FruitCardUserConvert.INSTANCE.convert(updateReqVO);
        cardUserMapper.updateById(updateObj);
    }

    @Override
    public void deleteCardUser(Long id) {
        // 校验存在
        validateCardUserExists(id);
        // 删除
        cardUserMapper.deleteById(id);
    }

    private void validateCardUserExists(Long id) {
        if (cardUserMapper.selectById(id) == null) {
//            throw exception(CARD_USER_NOT_EXISTS);
        }
    }

    @Override
    public FruitCardUserDO getCardUser(Long id) {
        return cardUserMapper.selectById(id);
    }

    @Override
    public List<FruitCardUserDO> getCardUserList(Collection<Long> ids) {
        return cardUserMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<FruitCardUserRespVO> getCardUserPage(FruitCardUserPageReqVO pageReqVO) {
        List<Long> cardNoRelativeIds;
        if (StringUtils.hasText(pageReqVO.getCardNo())) {
            List<FruitCardDetailDO> fruitCardDetailDOS = fruitCardDetailMapper.selectList(
                    Wrappers.<FruitCardDetailDO>lambdaQuery()
                            .eq(FruitCardDetailDO::getStatus, Boolean.TRUE)
                            .like(FruitCardDetailDO::getCardNo, pageReqVO.getCardNo())
            );


            if (ObjectUtils.isEmpty(fruitCardDetailDOS)) {
                return PageResult.empty();
            }
            cardNoRelativeIds = fruitCardDetailDOS.stream().map(FruitCardDetailDO::getId).collect(Collectors.toList());
            pageReqVO.setCardNoRelativeIds(cardNoRelativeIds);
        }
        PageResult<FruitCardUserDO> pageResult = cardUserMapper.selectPage(pageReqVO);
        PageResult<FruitCardUserRespVO> result = FruitCardUserConvert.INSTANCE.convertPage(pageResult);
        if (ObjectUtils.isEmpty(result) || CollectionUtils.isEmpty(result.getList())) {
            return result;
        }
        List<Long> detailIds =
                result.getList().stream().map(FruitCardUserBaseVO::getDetailId).collect(Collectors.toList());
        List<FruitCardDetailDO> detailDOS = fruitCardDetailMapper.selectBatchIds(detailIds);

        result.getList().forEach(r -> {
            detailDOS.stream().filter(d -> d.getId().equals(r.getDetailId())).findFirst().ifPresent(d -> {
                r.setCardNo(d.getCardNo());
                r.setActivationTime(d.getActivationTime());
                r.setExpiredTime(d.getExpiredTime());
                r.setUses(d.getUses());
            });
        });
        return result;
    }

    @Override
    public List<FruitCardUserDO> getCardUserList(FruitCardUserExportReqVO exportReqVO) {
        return cardUserMapper.selectList(exportReqVO);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public AppFruitCardBindRespVO bind(AppFruitCardBindReqVO vo, Long loginUserId) {
        // 校验卡号密码
        FruitCardDetailDO fruitCardDetailDO = fruitCardDetailMapper.selectOne(
                Wrappers.<FruitCardDetailDO>lambdaQuery()
                        .eq(FruitCardDetailDO::getCardNo, vo.getCardNo())
                        .eq(FruitCardDetailDO::getCardPwd, vo.getCardPwd())
        );
        if (ObjectUtils.isEmpty(fruitCardDetailDO)) {
            throw exception(NO_OR_PWD_ERROR);
        }
        if (fruitCardDetailDO.getStatus()) {
            throw exception(DO_NOT_REPEAT_BIND);
        }

        FruitCardDO fruitCardDO = fruitCardMapper.selectById(fruitCardDetailDO.getFruitCardId());

        // 关联到用户
        FruitCardUserDO cardUser = new FruitCardUserDO();
        cardUser.setUserId(loginUserId);
        cardUser.setDetailId(fruitCardDetailDO.getId());
        cardUser.setPhone(memberUserApi.getUser(loginUserId).getMobile());
        cardUser.setCardId(fruitCardDetailDO.getFruitCardId());
        cardUserMapper.insert(cardUser);

        // 修改当前卡号状态
        LocalDateTime now = LocalDateTime.now();
        fruitCardDetailMapper.update(null,
                Wrappers.<FruitCardDetailDO>lambdaUpdate()
                        .set(FruitCardDetailDO::getActivationTime, now)
                        .set(FruitCardDetailDO::getExpiredTime, now.plusMonths(fruitCardDO.getValidMonth()))
                        .set(FruitCardDetailDO::getStatus, 1)
                        .eq(FruitCardDetailDO::getId, fruitCardDetailDO.getId())
        );

        AppFruitCardBindRespVO appFruitCardBindRespVO = new AppFruitCardBindRespVO();
        appFruitCardBindRespVO.setCardDetailId(fruitCardDetailDO.getId());
        appFruitCardBindRespVO.setTimes(fruitCardDO.getTimes());
        appFruitCardBindRespVO.setDescription(fruitCardDO.getDescription());
        appFruitCardBindRespVO.setCardNo(fruitCardDetailDO.getCardNo());
        appFruitCardBindRespVO.setValidMonth(fruitCardDO.getValidMonth());
        appFruitCardBindRespVO.setFruitType(fruitCardDO.getFruitType());
        return appFruitCardBindRespVO;

    }

    @Override
    public PageResult<AppFruitCardRespVO> cardsPage(AppFruitCardPageReqVO pageReqVO, Long loginUserId) {

        PageResult<FruitCardUserDO> pageResult =
                cardUserMapper.selectPage(pageReqVO, Wrappers.<FruitCardUserDO>lambdaQuery().eq(FruitCardUserDO::getUserId, loginUserId));

        if (ObjectUtils.isEmpty(pageResult) || CollectionUtils.isEmpty(pageResult.getList())) {
            return PageResult.empty();
        }
        PageResult<AppFruitCardRespVO> convertedPageApp =
                FruitCardUserConvert.INSTANCE.convertPageApp(pageResult);

        List<Long> cardIds =
                pageResult.getList().stream().map(FruitCardUserDO::getCardId).collect(Collectors.toList());
        List<Long> detailIds =
                pageResult.getList().stream().map(FruitCardUserDO::getDetailId).collect(Collectors.toList());

        List<FruitCardDO> fruitCardDOS = fruitCardMapper.selectBatchIds(cardIds);
        List<FruitCardDetailDO> fruitCardDetailDOS = fruitCardDetailMapper.selectBatchIds(detailIds);


        List<DictDataRespDTO> fruitType = dataApi.getDictDataList("fruit_type");

        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(fruitCardDOS.stream().map(FruitCardDO::getFruitType).map(Long::valueOf).collect(Collectors.toList()));


        convertedPageApp.getList().forEach(r -> {


            fruitCardDOS.stream().filter(d -> d.getId().equals(r.getCardId())).findFirst().ifPresent(d -> {
                r.setCardType(d.getCardType());
                r.setTimes(d.getTimes());
                r.setDescription(d.getDescription());
                r.setValidMonth(d.getValidMonth());

                r.setFruitType(d.getFruitType());
                r.setCardType(d.getCardType());

                r.setFruitTypeName(
                        spuList.stream().filter(f -> f.getId().equals(Long.valueOf(d.getFruitType()))).findFirst().map(ProductSpuRespDTO::getName).orElse(null)
                );

                r.setCardTypeName(
                        fruitType.stream().filter(f -> f.getValue().equals(d.getFruitType())).findFirst().map(DictDataRespDTO::getLabel).orElse(null)
                );

            });
            fruitCardDetailDOS.stream().filter(d -> d.getId().equals(r.getDetailId())).findFirst().ifPresent(d -> {
                r.setCardNo(d.getCardNo());
                r.setActivationTime(d.getActivationTime());
                r.setExpiredTime(d.getExpiredTime());
                if (!ObjectUtils.isEmpty(d.getExpiredTime())) {
                    r.setIsExpire(LocalDateTime.now().isBefore(d.getExpiredTime()));
                }
                r.setUses(d.getUses());
            });


//            List<AppFruitCardRespVO.TimesDetail> list = new ArrayList<>();
//            AppFruitCardRespVO.TimesDetail timesDetail = new AppFruitCardRespVO.TimesDetail();
//            timesDetail.setSort(1);
//            timesDetail.setOrderNo("o202312211349031");
//            timesDetail.setExpressNo("11121212");
//            timesDetail.setTitle("海南黑金刚莲雾");
//            timesDetail.setStatus("3");
//            timesDetail.setBeginDate("2023-02-02");
//            timesDetail.setUrl("https://app.jxzx2023.com.cn/admin-api/infra/file/4/get/f7cd250c2c923979625187f61f0427302363cc0fad6c0010057a0207dac0eb09.png");
//            timesDetail.setConfirmDate("2023-02-02");
//            list.add(timesDetail);
//
//            AppFruitCardRespVO.TimesDetail timesDetail2 = new AppFruitCardRespVO.TimesDetail();
//            timesDetail2.setSort(2);
//            timesDetail2.setOrderNo("o202312211359371");
//            timesDetail2.setExpressNo("11121212");
//            timesDetail2.setTitle("麒麟燕窝果");
//            timesDetail2.setStatus("2");
//            timesDetail2.setUrl("https://app.jxzx2023.com.cn/admin-api/infra/file/4/get/f795a4669a13f2cf1a1f80e775034d2e88521f973f90cec7661bdb7e9deae1a3.png");
//            timesDetail2.setBeginDate("2023-03-02");
//            list.add(timesDetail2);
//
//            AppFruitCardRespVO.TimesDetail timesDetail3 = new AppFruitCardRespVO.TimesDetail();
//            timesDetail3.setSort(2);
//            timesDetail3.setStatus("0");
//            timesDetail3.setBeginDate("2023-04-01");
//            list.add(timesDetail3);
//            r.setDetailList(list);

        });


        List<FruitCardUsesDO> fruitCardUsesDOS = fruitCardUsesMapper.selectList(Wrappers
                .<FruitCardUsesDO>lambdaQuery()
                .in(FruitCardUsesDO::getDetailId, detailIds)
                .orderByAsc(BaseDO::getCreateTime)
        );

        if (CollectionUtils.isEmpty(fruitCardUsesDOS)) {
            return convertedPageApp;
        }
        List<TradeOrderDO> orderDOS =
                tradeOrderMapper
                        .selectList(TradeOrderDO::getId, fruitCardUsesDOS.stream().map(FruitCardUsesDO::getOrderId).collect(Collectors.toSet()));
        if (CollectionUtils.isEmpty(orderDOS)) {
            return convertedPageApp;
        }

        List<TradeOrderItemDO> tradeOrderItemDOS = tradeOrderItemMapper
                .selectList(TradeOrderItemDO::getOrderId, fruitCardUsesDOS.stream().map(FruitCardUsesDO::getOrderId).collect(Collectors.toSet()));
        if (CollectionUtils.isEmpty(tradeOrderItemDOS)) {
            return convertedPageApp;
        }

        List<TradeOrderItemOtherDO> tradeOrderItemOtherDOS = tradeOrderItemOtherMapper
                .selectList(TradeOrderItemOtherDO::getOrderId, fruitCardUsesDOS.stream().map(FruitCardUsesDO::getOrderId).collect(Collectors.toSet()));
        if (CollectionUtils.isEmpty(tradeOrderItemOtherDOS)) {
            return convertedPageApp;
        }

        List<DeliveryExpressDO> expressDOS = deliveryExpressMapper.selectList();

        Map<Long, List<FruitCardUsesDO>> usesMap = fruitCardUsesDOS.stream().collect(Collectors.groupingBy(FruitCardUsesDO::getDetailId));

        convertedPageApp.getList().forEach(r -> {

            if(usesMap.containsKey(r.getDetailId())){
                List<FruitCardUsesDO> uses = usesMap.get(r.getDetailId());
                List<AppFruitCardRespVO.TimesDetail> detailList = new ArrayList<>();


                uses.stream().forEach(u->{
                    orderDOS.stream().filter(o -> o.getId().equals(u.getOrderId())).findFirst().ifPresent(o->{
                        AppFruitCardRespVO.TimesDetail timesDetail = new AppFruitCardRespVO.TimesDetail();
                        timesDetail.setSort(uses.indexOf(u)+1);
                        timesDetail.setOrderNo(o.getNo());

                        // 状态 0--未开始  1--待发货 2--已发货 3 --已完成
                        if(o.getStatus().equals(TradeOrderStatusEnum.UNDELIVERED.getStatus() )){
                            timesDetail.setStatus("1");
                        }else if(o.getStatus().equals(TradeOrderStatusEnum.DELIVERED.getStatus() )){
                            timesDetail.setStatus("2");
                        }else if(o.getStatus().equals(TradeOrderStatusEnum.COMPLETED.getStatus() )){
                            timesDetail.setStatus("3");
                        }


                        tradeOrderItemDOS.stream().filter( i -> i.getOrderId().equals(o.getId())).findFirst().ifPresent(i->{

                            expressDOS.stream().filter(e -> e.getId().equals(i.getLogisticsId())).findFirst().ifPresent(e->{
                                timesDetail.setExpressNo(e.getName()+":"+i.getLogisticsNo());
                            });
                            i.getLogisticsId();
                            timesDetail.setExpressNo(i.getLogisticsNo());

                            timesDetail.setTitle(i.getSpuName());
                            timesDetail.setUrl(i.getPicUrl());

                        });

                        if(o.getDeliveryMode().equals(1)){


                        }else if(o.getDeliveryMode().equals(2)){


                        }


                        timesDetail.setBeginDate(DateUtil.formatLocalDateTime(o.getCreateTime()));
                        timesDetail.setConfirmDate(DateUtil.formatLocalDateTime(o.getFinishTime()));
                        detailList.add(timesDetail);

                    });

                });

                r.setDetailList(
                        detailList
                );
                r.setUses(uses.size());
            }

        });

        return convertedPageApp;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public AppFruitCardExchangeRespVO exchange(AppFruitCardExchangeReqVO vo, Long loginUserId, String clientIP) {

        //  判断有没有资格可以兑换
        FruitCardDetailDO detail = fruitCardDetailMapper.selectById(vo.getCardDetailId());
        if (ObjectUtils.isEmpty(detail)) {
            throw exception(CARD_NOT_EXISTS);
        }

        FruitCardDO fruitCardDO = fruitCardMapper.selectById(vo.getCardId());
        if (detail.getUses() >= fruitCardDO.getTimes()) {
            throw exception(CARD_USES_OVER);
        }
        if (LocalDateTime.now().isAfter(detail.getExpiredTime())) {
            throw exception(CARD_HAS_EXPIRED);
        }


        AppFruitCardExchangeRespVO respVO = new AppFruitCardExchangeRespVO();
        // 生成订单
        // 1.1 价格计算,水果卡兑换，价格为0
        Integer payPrice = 0;
        // 1.2 构建订单
        Set<Long> collect = vo.getItems().stream().map(AppFruitCardExchangeReqVO.Item::getSkuId).collect(Collectors.toSet());
        List<ProductSkuRespDTO> skuList = productSkuApi.getSkuList(collect);

        TradeOrderDO order = buildTradeOrder(loginUserId, clientIP, vo);
        TradePriceCalculateRespBO calculateRespBO = new TradePriceCalculateRespBO();
        calculateRespBO.setType(TradeOrderTypeEnum.FRUITCARD.getType());
        TradePriceCalculateRespBO.Price price = new TradePriceCalculateRespBO.Price();
        order.setTotalPrice(skuList.stream().map(ProductSkuRespDTO::getPrice).reduce(0, Integer::sum));
        order.setDiscountPrice(0);
        order.setDeliveryPrice(0);
        order.setPayPrice(0);
        order.setCouponPrice(0);
        order.setPointPrice(0);
        order.setVipPrice(0);

        price.setTotalPrice(skuList.stream().map(ProductSkuRespDTO::getPrice).reduce(0, Integer::sum));
        price.setPayPrice(payPrice);
        calculateRespBO.setPrice(price);


        List<ProductSpuRespDTO> spuList = productSpuApi.getSpuList(skuList.stream().map(ProductSkuRespDTO::getSpuId).collect(Collectors.toSet()));

        calculateRespBO.setItems(skuList == null ? Lists.newArrayList() : skuList.stream().map(sku -> {
            TradePriceCalculateRespBO.OrderItem orderItem = new TradePriceCalculateRespBO.OrderItem();

            orderItem.setSpuName(spuList. stream().filter(spu -> spu.getId().equals(sku.getSpuId())).findFirst().map(ProductSpuRespDTO::getName).orElse(null));
            orderItem.setSkuId(sku.getId());
            orderItem.setSpuId(sku.getSpuId());
            orderItem.setCount(
                    vo.getItems().stream().filter(item -> item.getSkuId().equals(sku.getId())).findFirst().map(AppFruitCardExchangeReqVO.Item::getCount).orElse(0)
            );
            orderItem.setPrice(sku.getPrice());
            orderItem.setPayPrice(payPrice);

            orderItem.setDiscountPrice(0);
            orderItem.setDeliveryPrice(0);
            orderItem.setCouponPrice(0);
            orderItem.setPointPrice(0);
            orderItem.setVipPrice(0);

            return orderItem;
        }).collect(Collectors.toList()));
        List<TradeOrderItemDO> orderItems = TradeOrderConvert.INSTANCE.convertList(order, calculateRespBO);

        // 2. 订单创建前的逻辑
        tradeOrderHandlers.forEach(handler -> handler.beforeOrderCreate(order, orderItems));

        // 3. 保存订单
        tradeOrderMapper.insert(order);
        orderItems.forEach(orderItem -> orderItem.setOrderId(order.getId()));
        tradeOrderItemMapper.insertBatch(orderItems);


        // 4. 订单创建后的逻辑,跳过支付
        tradeOrderHandlers.forEach(handler -> handler.afterOrderCreate(order, orderItems));
        TradeOrderLogUtils.setOrderInfo(order.getId(), null, order.getStatus());

        // 次数更新
        fruitCardDetailMapper.update(null, Wrappers.<FruitCardDetailDO>lambdaUpdate()
                .eq(FruitCardDetailDO::getId, vo.getCardDetailId())
                .set(FruitCardDetailDO::getUses, detail.getUses() + 1)
        );


        // 生成使用记录
        FruitCardUsesDO use = new FruitCardUsesDO();
        use.setUserId(loginUserId);
        use.setDetailId(Long.valueOf(vo.getCardDetailId()));
        use.setOrderId(order.getId());
        use.setOrderNo(order.getNo());
        fruitCardUsesMapper.insert(use);
        return respVO;
    }

    @Override
    public void updateCardStatus(FruitCardUpdateStatusReqVO updateReqVO) {
        cardUserMapper.update(null, Wrappers.<FruitCardUserDO>lambdaUpdate().eq(FruitCardUserDO::getId, updateReqVO.getId()).set(FruitCardUserDO::getStatus, updateReqVO.getStatus()));
    }


    private TradeOrderDO buildTradeOrder(Long userId, String clientIp, AppFruitCardExchangeReqVO createReqVO) {
        TradeOrderDO order = new TradeOrderDO();
        order.setUserId(userId);
        order.setUserIp(clientIp);
        order.setType(TradeOrderTypeEnum.FRUITCARD.getType());
        order.setNo(tradeNoRedisDAO.generate(TradeNoRedisDAO.TRADE_ORDER_NO_PREFIX));
        order.setStatus(TradeOrderStatusEnum.UNDELIVERED.getStatus());
        order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus());
        order.setProductCount(1);
        order.setTerminal(TerminalEnum.WECHAT_MINI_PROGRAM.getTerminal());
        // 支付 + 退款信息
        order.setAdjustPrice(0).setPayStatus(false);
        order.setRefundStatus(TradeOrderRefundStatusEnum.NONE.getStatus()).setRefundPrice(0);
        // 物流信息
        order.setDeliveryType(createReqVO.getDeliveryType());
        if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.EXPRESS.getType())) {
            MemberAddressRespDTO address = addressApi.getAddress(createReqVO.getAddressId(), userId);
            Assert.notNull(address, "地址({}) 不能为空", createReqVO.getAddressId()); // 价格计算时，已经计算
            order.setReceiverName(address.getName()).setReceiverMobile(address.getMobile())
                    .setReceiverAreaId(address.getAreaId()).setReceiverDetailAddress(address.getDetailAddress());
        } else if (Objects.equals(createReqVO.getDeliveryType(), DeliveryTypeEnum.PICK_UP.getType())) {
            order.setReceiverName(createReqVO.getReceiverName()).setReceiverMobile(createReqVO.getReceiverMobile());
            order.setPickUpVerifyCode(RandomUtil.randomNumbers(8)); // 随机一个核销码，长度为 8 位
        }
        return order;
    }


}
